Skip to content

[IMP] purchase: add global discount support on RFQ lines#1160

Draft
mekot-odoo wants to merge 4 commits intoodoo:19.0from
odoo-dev:19.0-purchase-global-discount-mekot
Draft

[IMP] purchase: add global discount support on RFQ lines#1160
mekot-odoo wants to merge 4 commits intoodoo:19.0from
odoo-dev:19.0-purchase-global-discount-mekot

Conversation

@mekot-odoo
Copy link

This PR introduces a global discount mechanism that allows users to
apply a percentage or fixed amount discount across all RFQ lines in a
single action, improving usability and efficiency.

This commit introduces a global discount mechanism that allows users to
apply a percentage or fixed amount discount across all RFQ lines in a
single action, improving usability and efficiency.
Prevented division by zero when converting a fixed discount
to percentage if the RFQ untaxed amount is zero.
@robodoo
Copy link

robodoo commented Feb 13, 2026

Pull request status dashboard

@mekot-odoo mekot-odoo marked this pull request as draft February 13, 2026 05:13
Adjusted the placement of the Discount button in the purchase order
form view to align it to the right side for better visibility and
usability when applying global discounts.
Copy link

@kcv-odoo kcv-odoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR!

It seems not working properly and giving weird behavior in different cases, Can you explain bit more about what you did? why you did?

From functional POV:

  • In one case, the amount becomes 0, and in another case it shows 10 after applying the global discount.

  • Issue with Global Discount Update: If I change the global discount from 10 to 1, the amount becomes 0, which should not happen.
    The current logic (especially in the wizard) does not seem correct and needs to be reviewed.

could you try to make it work Properly according to Specs and add remaining things missing from the specs

@bit-odoo Did you reviewed this task? as it seems wrong and not working properly

Have a nice day!

Comment on lines 15 to 36
@api.depends("discount", "discount_type")
def _calculate_percentage(self):
order = self.env["purchase.order"].browse(self.env.context.get("active_id"))
if self.discount_type == "percent":
self.discount_percent = self.discount
elif order.amount_untaxed != 0:
self.discount_percent = (self.discount * 100) / order.amount_untaxed
else:
self.discount_percent = 0

def action_apply_discount(self):
order = self.env["purchase.order"].browse(self.env.context.get("active_id"))
if self.discount_type == "percent":
order.order_line.write({"discount": self.discount})
elif order.amount_untaxed != 0:
order.order_line.write({"discount": 0})
self.discount = (self.discount * 100) / order.amount_untaxed
order.order_line.write({"discount": self.discount})
else:
raise UserError(
"Cannot apply fixed discount because Total Amount is already zero."
)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems so wrong and giving me very weird behaviors, Could you try to understand it more and make it work properly? You can take inspiration from Discount on SO and Loyalty module or even try to use it's logic but it should not give any weird behavior 😉

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Hello! Thank you for the feedback. After further investigation, I identified why the behavior was inconsistent: my previous logic was calculating the discount against the current amount_untaxed, which already included previous discounts. This caused the total to drift incorrectly when updating the value (e.g., changing from 10% to 1%).

To fix this and align with the standard logic used in SO/Loyalty:

Consistent Base: I am refactoring the calculation to use the Base Untaxed Amount (Sum of price_unit * product_qty) so the discount is always calculated against the original 100% value.

Standard Write: I’m removing the manual reset to zero and instead performing a single, clean write() to the lines based on this consistent base total.

Validation: I'm adding constraints to ensure the discount stays within a logical 0-100% range.

Comment on lines 8 to 21
<form>
<field name="discount"/>
<field name="discount_type" nolabel="True"/>
<span class="text-muted">
(
<field name="discount_percent" nolabel="1"/>
%
)
</span>
<footer>
<button name="action_apply_discount" string="Apply" type="object" class="btn btn-primary"/>
<button special="cancel" string="Discard" class="btn btn-secondary" data-hotkey="x"/>
</footer>
</form>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make it more user friendly currently is seems very ugly 🙁

Comment on lines 9 to 10
"application": True,
"installable": True,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should not be application and auto_install should be true

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the suggestion.

I’ve updated the manifest accordingly — the module is no longer marked as an application, and auto_install has been set to True.

Comment on lines 7 to 15
def action_purchase_global_discount(self):
self.ensure_one()
return {
"name": "Discount",
"type": "ir.actions.act_window",
"res_model": "purchase.order.discount",
"view_mode": "form",
"target": "new",
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make button type="action instead object

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve replaced the object method call with a type="action" button and linked it directly to the corresponding window action.

@@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_purchase_order_discount,access_purchase_order_discount,model_purchase_order_discount,base.group_user,1,1,1,1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really useful for non purchase user?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for pointing it out.

You’re right — granting access to base.group_user would allow all internal users to manage purchase order discount records, which is not necessary. This feature is intended to be used only by purchase users.

I will update the access rights to restrict it to group_purchase_user instead of all internal users.

Compute the discount using the sum of (price_unit * quantity) instead of
amount_untaxed to avoid inconsistent results when updating discounts.

Add a constraint to restrict the discount percentage between 0 and 100
and properly initialize the base amount to prevent UnboundLocalError.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants